use crate::allocator::Heap;

pub struct Simulator {
    heap: Heap,
}

impl Simulator {
    pub fn new() -> Self {
        Self { heap: Heap::new(1) }
    }

    pub fn run(&mut self) {
        debug_log!("\n=== Basic Allocation Test ===");
        self.test_small_allocation();

        debug_log!("\n=== Multiple Allocations Test ===");
        self.test_multiple_allocations();

        debug_log!("\n=== Free List Test ===");
        self.test_free_list();
    }

    fn test_small_allocation(&mut self) {
        let size = 24;
        if let Some(ptr) = self.heap.allocate(size) {
            debug_log!("Successfully allocated {} bytes at {:?}", size, ptr);
            self.heap.deallocate(ptr);
            debug_log!("Successfully deallocated memory at {:?}", ptr);
        }
    }

    fn test_multiple_allocations(&mut self) {
        let mut ptrs = Vec::new();

        // Allocate multiple blocks
        for size in [24, 48, 96, 192].iter() {
            if let Some(ptr) = self.heap.allocate(*size) {
                debug_log!("Allocated {} bytes at {:?}", size, ptr);
                ptrs.push((ptr, *size));
            }
        }

        // Deallocate in reverse order
        while let Some((ptr, _size)) = ptrs.pop() {
            debug_log!("Deallocating pointer at {:?}", ptr);
            self.heap.deallocate(ptr);
        }
    }

    fn test_free_list(&mut self) {
        let size = 24;
        let mut ptrs = Vec::new();

        // Allocate several blocks
        for _idx in 0..5 {
            if let Some(ptr) = self.heap.allocate(size) {
                debug_log!("Allocation {}: {:?}", _idx, ptr);
                ptrs.push(ptr);
            }
        }

        // Free them in reverse order
        while let Some(ptr) = ptrs.pop() {
            debug_log!("Deallocating: {:?}", ptr);
            self.heap.deallocate(ptr);
        }

        // Allocate again to test free list reuse
        debug_log!("\nTesting free list reuse:");
        for _idx in 0..3 {
            if let Some(ptr) = self.heap.allocate(size) {
                debug_log!("Reallocation {}: {:?}", _idx, ptr);
                self.heap.deallocate(ptr);
            }
        }
    }
}
